using UnityEngine;
using System.Collections.Generic;

public class BM_InputManager : MonoBehaviour
{
	public enum PlatformFamily
	{
		INPUT_NONE = -1
		
	,	INPUT_TOUCH
	,	INPUT_MOUSE
	,	INPUT_GAMEPAD
		
	,	INPUT_COUNT
	}
	
	public enum GestureName
	{
		GESTURE_NONE = -1
	,	GESTURE_PINCH
	,	GESTURE_SPREAD
	,	GESTURE_SCROLL
	,	GESTURE_SWIPE
	}
	
	public enum GPButtonName
	{
		GB_NONE = -1
		
	,	GB_SELECT
	,	GB_BACK	
	,	GB_LEFTBUMP
	,	GB_RIGHTBUMP
	,	GB_X
	,	GB_Y
	,	GB_START

	,	GB_COUNT
	}
	
	public enum GPButtonStateName
	{
		GBS_NONE = -1
	,	GBS_IDLE
	,	GBS_PRESSED
	,	GBS_HOLD
	,	GBS_RELEASED
	}
	
	private class GamepadButtonState
	{
		private string				m_strButtonName;
		private bool				m_bPreviousButtonState;
		private bool				m_bCurrentButtonState;
		
		public GamepadButtonState(string strButtonName)
		{
			m_strButtonName = strButtonName;
		}
		
		public GPButtonStateName ButtonState
		{
			get
			{
				GPButtonStateName eRVal = GPButtonStateName.GBS_NONE;
				if(!m_bPreviousButtonState && !m_bCurrentButtonState)
					eRVal = GPButtonStateName.GBS_IDLE;
				else if(!m_bPreviousButtonState && m_bCurrentButtonState)
					eRVal = GPButtonStateName.GBS_PRESSED;
				else if(m_bPreviousButtonState && m_bCurrentButtonState)
					eRVal = GPButtonStateName.GBS_HOLD;
				else if(m_bPreviousButtonState && !m_bCurrentButtonState)
					eRVal = GPButtonStateName.GBS_RELEASED;
				return eRVal;
			}
		}
		
		public void Update()
		{
			m_bPreviousButtonState = m_bCurrentButtonState;
			
			string strPlatform = (Application.platform == RuntimePlatform.Android) ? "Android_" : "Win32_";
			m_bCurrentButtonState = (Time.timeScale > 0.0f) ? (Input.GetAxis(strPlatform+m_strButtonName) != 0.0f) : (Input.GetAxisRaw(strPlatform+m_strButtonName) != 0.0f);
		}
	}
	
	private class KeyboardButtonState
	{
		private KeyCode				m_eButtonName;
		private GPButtonStateName	m_eCurrentButtonState;
		
		public KeyboardButtonState(KeyCode eButtonName)
		{
			m_eButtonName = eButtonName;
			m_eCurrentButtonState = GPButtonStateName.GBS_IDLE;
		}
		
		public GPButtonStateName ButtonState
		{
			get { return m_eCurrentButtonState; }
		}
		
		public void Update()
		{
			
			m_eCurrentButtonState = BM_InputManager.GPButtonStateName.GBS_IDLE;
			if(Input.GetKeyDown(m_eButtonName))
				m_eCurrentButtonState = BM_InputManager.GPButtonStateName.GBS_PRESSED;
			else if(Input.GetKeyUp(m_eButtonName))
				m_eCurrentButtonState = BM_InputManager.GPButtonStateName.GBS_RELEASED;
			else if(Input.GetKey(m_eButtonName))
				m_eCurrentButtonState = BM_InputManager.GPButtonStateName.GBS_HOLD;
		}
	}
	
	public class GestureInfo
	{
		public GestureName		m_eGestureName = BM_InputManager.GestureName.GESTURE_NONE;
		public Vector3			m_vGestureData_1 = Vector3.zero;
		public float			m_fGestureData_2 = 0.0f;
	}
	
	public class EMAInfo
	{
		public float		m_EMA_AlphaWeight = 1.0f;
		public Vector3		m_EMA_StartingValue = Vector3.zero;
		public Vector3		m_EMA_MeanValue = Vector3.zero;
		public Vector3		m_EMA_MeanValueDiff = Vector3.zero;
	}
	
	public class SV_TouchInfo
	{
		public PlatformFamily	m_ePlatform = BM_InputManager.PlatformFamily.INPUT_NONE;
		public int				m_iFingerIndex = -1;
		public Vector3			m_vPosition = Vector3.zero;
		public TouchPhase		m_eTouchPhase = TouchPhase.Canceled;
	}
	
	
	#region Members	
	
		// touch
	private bool[]				m_vTouchEmulationDevices = null;
	private SV_TouchInfo[][]	m_vCurrentTouches = null;

		// gestures
	private int[]				m_vTouchIndex = { -1, -1 };
	private float				m_fPinchSpreadDistance = 50.0f;
	private float				m_fStartDistance = 0.0f;

	private readonly float				m_fEMA_MIN_AlphaWeight = 0.1f;
	private readonly float				m_fEMA_DELTA_AlphaWeight = 0.1f;
	private readonly float				m_fSwipeThreshold = 10.0f;
	private Dictionary<int, EMAInfo>	m_vTouchHistories = null;
	
	private List<GestureInfo>	m_vCurrentGestures = null;
	
		// gamepad	
	private float		m_fPreviousTimestamp = 0.0f;
	private Vector3		m_vGamepadPointerPos = Vector3.zero;
	private float		m_fGamepadPointerSpeed = 500.0f;
	private float		m_fGamepadPointerSpeedRatio = 1.0f;
	private string[]	m_strLeftStickNames = { "LeftStick_X", "LeftStick_Y" };
	private string		m_strTriggerName = "Triggers";
	
	private Dictionary<GPButtonName, GamepadButtonState> m_sDictGamepadButtonStates = new Dictionary<GPButtonName, GamepadButtonState>
	{
		{ GPButtonName.GB_SELECT,		new GamepadButtonState("A") }
	,	{ GPButtonName.GB_BACK,			new GamepadButtonState("B") }	
	,	{ GPButtonName.GB_LEFTBUMP,		new GamepadButtonState("LeftBump") }
	,	{ GPButtonName.GB_RIGHTBUMP,	new GamepadButtonState("RightBump") }
	,	{ GPButtonName.GB_X,			new GamepadButtonState("X") }	
	,	{ GPButtonName.GB_Y,			new GamepadButtonState("Y") }	
	,	{ GPButtonName.GB_START,		new GamepadButtonState("Start") }
	};
	
	private Dictionary<KeyCode, KeyboardButtonState> m_sDictKeyboardButtonStates = null;
	
	#endregion	
	
	
	#region Properties
	
	public PlatformFamily ActiveDevice
	{
		get
		{
			PlatformFamily eRVal = PlatformFamily.INPUT_NONE;
			if(GetTouchEmulationInputDeviceState(PlatformFamily.INPUT_TOUCH) && GetTouchesCountFromType(PlatformFamily.INPUT_TOUCH) > 0)
				eRVal = PlatformFamily.INPUT_TOUCH;
			else if(GetTouchEmulationInputDeviceState(PlatformFamily.INPUT_MOUSE) && GetTouchesCountFromType(PlatformFamily.INPUT_MOUSE) > 0)
				eRVal = PlatformFamily.INPUT_MOUSE;
			else if(GetTouchEmulationInputDeviceState(PlatformFamily.INPUT_GAMEPAD) && GetTouchesCountFromType(PlatformFamily.INPUT_GAMEPAD) > 0)
				eRVal = PlatformFamily.INPUT_GAMEPAD;
			return eRVal;
		}
	}
	
	private PlatformFamily ActiveDevice_Internal
	{
		get
		{
			PlatformFamily eRVal = PlatformFamily.INPUT_NONE;
			if(GetTouchEmulationInputDeviceState(PlatformFamily.INPUT_TOUCH) && GetTouchesCountFromType_Internal(PlatformFamily.INPUT_TOUCH) > 0)
				eRVal = PlatformFamily.INPUT_TOUCH;
			else if(GetTouchEmulationInputDeviceState(PlatformFamily.INPUT_MOUSE) && GetTouchesCountFromType_Internal(PlatformFamily.INPUT_MOUSE) > 0)
				eRVal = PlatformFamily.INPUT_MOUSE;
			else if(GetTouchEmulationInputDeviceState(PlatformFamily.INPUT_GAMEPAD) && GetTouchesCountFromType_Internal(PlatformFamily.INPUT_GAMEPAD) > 0)
				eRVal = PlatformFamily.INPUT_GAMEPAD;
			return eRVal;
		}
	}

	
	#region Touch
	
	public bool IsTouching
	{
		get { return (GetTouchesCountFromType(ActiveDevice) > 0); }
	}
	
	public Vector3 PointerPosition
	{
		get
		{
			Vector3 vRVal = Vector3.zero;
			SV_TouchInfo[] vTouches = GetDeviceTouches(ActiveDevice);
			if(vTouches != null)
				vRVal = vTouches[0].m_vPosition;
			return vRVal;
		}
	}
	
	public List<GestureInfo> Gestures
	{
		get { return m_vCurrentGestures; }
	}
	
	#endregion

	
	#region Gamepad
	
	public bool IsLeftStickMoving
	{
		get
		{
			string strPlatform = (Application.platform == RuntimePlatform.Android) ? "Android_" : "Win32_";
			return (Input.GetAxis(strPlatform+m_strLeftStickNames[0]) != 0.0f || Input.GetAxis(strPlatform+m_strLeftStickNames[1]) != 0.0f);
		}
	}
	
	public bool IsTriggerMoving
	{
		get
		{
			string strPlatform = (Application.platform == RuntimePlatform.Android) ? "Android_" : "Win32_";
			return (Input.GetAxis(strPlatform+m_strTriggerName) != 0.0f);
		}
	}
	
	public float GamepadTriggerValue
	{
		get
		{
			string strPlatform = (Application.platform == RuntimePlatform.Android) ? "Android_" : "Win32_";
			return Input.GetAxis(strPlatform+m_strTriggerName);
		}
	}
	
	public Vector2 GamepadLeftStickValue
	{
		get
		{
			string strPlatform = (Application.platform == RuntimePlatform.Android) ? "Android_" : "Win32_";
			return new Vector2(Input.GetAxis(strPlatform+m_strLeftStickNames[1]), Input.GetAxis(strPlatform+m_strLeftStickNames[0]));
		}
	}
	
	public Vector3 GamepadPointerPosition
	{
		get { return m_vGamepadPointerPos; }
		set { m_vGamepadPointerPos = value; }
	}
	
	public SV_TouchInfo[] Touches
	{
		get { return GetDeviceTouches(ActiveDevice); }
	}
	
	#endregion
	
	#endregion
	
	
	public void Awake()
	{
		m_rManagerReference = this;
		
		m_vCurrentGestures = new List<GestureInfo>();
		m_vTouchHistories = new Dictionary<int, EMAInfo>();
			
		m_vTouchEmulationDevices = new bool[(int)PlatformFamily.INPUT_COUNT];
		for(int iDevice = 0; iDevice < m_vTouchEmulationDevices.Length; ++iDevice)
			m_vTouchEmulationDevices[iDevice] = false;
		SetTouchEmulationInputDevice(PlatformFamily.INPUT_TOUCH, true);
		
		m_fPreviousTimestamp = Time.realtimeSinceStartup;
		GamepadPointerPosition = new Vector3(Screen.width*0.5f, Screen.height*0.5f, 0.0f);
		
		m_sDictKeyboardButtonStates = new Dictionary<KeyCode, KeyboardButtonState>();
	}
	
	public void OnDestroy()
	{
		m_rManagerReference = null;
	}
	
	public void Update()
	{
		// update touches
		m_vCurrentTouches = ProcessNewTouches();
		UpdateGestures();		
//		UpdateGamepadState();
		UpdateKeyboardState();
	}
	
		
	#region Touch
	
	public void SetTouchEmulationInputDevice(PlatformFamily eDevice, bool bEnable)
	{
		if(eDevice != PlatformFamily.INPUT_NONE && eDevice != PlatformFamily.INPUT_COUNT)
			m_vTouchEmulationDevices[(int)eDevice] = bEnable;
	}
	
	public bool GetTouchEmulationInputDeviceState(PlatformFamily eDevice)
	{
		bool bRVal = false;
		if(eDevice != PlatformFamily.INPUT_NONE && eDevice != PlatformFamily.INPUT_COUNT)
			bRVal = m_vTouchEmulationDevices[(int)eDevice];
		return bRVal;
	}
	
	public int GetTouchesCountFromType(PlatformFamily ePlatform)
	{
		int iRVal = 0;
		
		if( GetTouchEmulationInputDeviceState(ePlatform) &&
			GetDeviceTouches(ePlatform) != null )
		{
			iRVal = GetDeviceTouches(ePlatform).Length;
		}
		
		return iRVal;
	}
	
	private int GetTouchesCountFromType_Internal(PlatformFamily ePlatform)
	{
		int iRVal = 0;
		
		if(GetTouchEmulationInputDeviceState(ePlatform))
		{
			switch(ePlatform)
			{
			case PlatformFamily.INPUT_TOUCH:
				iRVal = Input.touchCount;
				break;
				
			case PlatformFamily.INPUT_MOUSE:
				if(Input.GetMouseButton(0) || Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
					iRVal = 1;
				break;
				
			case PlatformFamily.INPUT_GAMEPAD:
				
				if(GetGamepadButtonState(GPButtonName.GB_SELECT) == GPButtonStateName.GBS_HOLD)
					iRVal = 1;
				break;
			}
		}
		
		return iRVal;
	}
	
	private SV_TouchInfo[] GetDeviceTouches(PlatformFamily eDevice)
	{
		SV_TouchInfo[] rRVal = null;
		
		if( m_vCurrentTouches != null &&
			eDevice != PlatformFamily.INPUT_NONE &&
			eDevice != PlatformFamily.INPUT_COUNT )
		{
			rRVal = m_vCurrentTouches[(int)eDevice];
		}
		
		return rRVal;
	}
	
	private SV_TouchInfo[][] ProcessNewTouches()
	{
		SV_TouchInfo[][] vRVal = new SV_TouchInfo[(int)PlatformFamily.INPUT_COUNT][];
		
		for(int iDevice = 0; iDevice < (int)PlatformFamily.INPUT_COUNT; ++iDevice)
		{
			vRVal[iDevice] = null;
			int iTouchesCount = GetTouchesCountFromType_Internal((PlatformFamily)iDevice);
			if(iTouchesCount > 0)
			{
				vRVal[iDevice] = new SV_TouchInfo[iTouchesCount];
				for(int iTouch = 0; iTouch < iTouchesCount; ++iTouch)
					vRVal[iDevice][iTouch] = new SV_TouchInfo();
				
				switch(ActiveDevice_Internal)
				{
				case PlatformFamily.INPUT_TOUCH:
					for(int iTouch = 0; iTouch < iTouchesCount; ++iTouch)
					{
						Touch touch = Input.GetTouch(iTouch);
						vRVal[iDevice][iTouch].m_ePlatform = PlatformFamily.INPUT_TOUCH;
						vRVal[iDevice][iTouch].m_iFingerIndex = touch.fingerId;
						vRVal[iDevice][iTouch].m_vPosition = touch.position;
						vRVal[iDevice][iTouch].m_eTouchPhase = touch.phase;
					}
					break;
					
				case PlatformFamily.INPUT_MOUSE:
					vRVal[iDevice][0].m_ePlatform = PlatformFamily.INPUT_MOUSE;
					vRVal[iDevice][0].m_iFingerIndex = 0;
					vRVal[iDevice][0].m_vPosition = Input.mousePosition;
					
					vRVal[iDevice][0].m_eTouchPhase = TouchPhase.Moved;
					if(Input.GetMouseButtonDown(0))
						vRVal[iDevice][0].m_eTouchPhase = TouchPhase.Began;
					else if(Input.GetMouseButtonUp(0))
						vRVal[iDevice][0].m_eTouchPhase = TouchPhase.Ended;
					
					break;
					
				case PlatformFamily.INPUT_GAMEPAD:
					
					vRVal[iDevice][0].m_ePlatform = PlatformFamily.INPUT_GAMEPAD;
					vRVal[iDevice][0].m_iFingerIndex = 0;
					vRVal[iDevice][0].m_vPosition = m_vGamepadPointerPos;
					
					vRVal[iDevice][0].m_eTouchPhase = TouchPhase.Moved;
					if(GetGamepadButtonState(GPButtonName.GB_SELECT) == GPButtonStateName.GBS_PRESSED)
						vRVal[iDevice][0].m_eTouchPhase = TouchPhase.Began;
					else if(GetGamepadButtonState(GPButtonName.GB_SELECT) == GPButtonStateName.GBS_RELEASED)
						vRVal[iDevice][0].m_eTouchPhase = TouchPhase.Ended;

					break;
				}
			}
			
		}
																			
		return vRVal;
	}
	
	private SV_TouchInfo GetTouchInfo(SV_TouchInfo[] vPointers, int iPointerIndex)
	{
		SV_TouchInfo rRVal = null;
		
		if(vPointers != null)
		{
			for(int iPointer = 0; (iPointer < vPointers.Length) && (rRVal == null); ++iPointer)
			{
				if(vPointers[iPointer].m_iFingerIndex == iPointerIndex)
					rRVal = vPointers[iPointer];
			}
		}
		
		return rRVal;
	}
	
	#endregion
	
	
	#region Gesture
	
	private void UpdateGestures()
	{
		m_vCurrentGestures.Clear();
		GestureInfo rGesture = CheckPinchSpreadScrollGestures();
		
		if(rGesture.m_eGestureName != GestureName.GESTURE_NONE)
			m_vCurrentGestures.Add(rGesture);
		
		List<GestureInfo> rSwipes = UpdateSwipesState();
		m_vCurrentGestures.AddRange(rSwipes);
	}
	
	
	private List<GestureInfo> UpdateSwipesState()
	{
		List<GestureInfo> vRVal = new List<GestureInfo>();
		Dictionary<int, EMAInfo> vNewHistories = new Dictionary<int, EMAInfo>();
		
		SV_TouchInfo[] vTouches = m_vCurrentTouches[(int)PlatformFamily.INPUT_TOUCH];
		if(vTouches != null)
		{
			for(int iPointer = 0; iPointer < vTouches.Length; ++iPointer)
			{
				int iCurrentFingerIndex = vTouches[iPointer].m_iFingerIndex;
				Vector3 vPosition = vTouches[iPointer].m_vPosition;
				
				// controllo se il tocco esisteva già al frame precedente
				EMAInfo rEMA = null;
				m_vTouchHistories.TryGetValue(iCurrentFingerIndex, out rEMA);
				
				if(rEMA == null)
				{
					rEMA = new EMAInfo();
					rEMA.m_EMA_StartingValue = vPosition;
				}
				
				// aggiorno la media mobile esponenziale dei valori
				rEMA.m_EMA_MeanValue = vPosition*rEMA.m_EMA_AlphaWeight + rEMA.m_EMA_MeanValue*(1-rEMA.m_EMA_AlphaWeight);
				rEMA.m_EMA_MeanValueDiff = rEMA.m_EMA_MeanValue - vPosition;
				
				// aggiorno il peso del valore corrente
				rEMA.m_EMA_AlphaWeight -= m_fEMA_DELTA_AlphaWeight;
				if(rEMA.m_EMA_AlphaWeight < m_fEMA_MIN_AlphaWeight)
					rEMA.m_EMA_AlphaWeight = m_fEMA_MIN_AlphaWeight;
				
				
				if(rEMA.m_EMA_MeanValueDiff.magnitude >= m_fSwipeThreshold)
				{
					GestureInfo rGesture = new GestureInfo();
					rGesture.m_eGestureName = GestureName.GESTURE_SWIPE;
					rGesture.m_vGestureData_1 = (rEMA.m_EMA_MeanValue-rEMA.m_EMA_StartingValue).normalized;
					rGesture.m_fGestureData_2 = rEMA.m_EMA_MeanValueDiff.magnitude;
					vRVal.Add(rGesture);
				}
				
				vNewHistories.Add(iCurrentFingerIndex, rEMA);
			}
		}
			
		// riassegno il dizionario di sequenze di tocchi
		m_vTouchHistories.Clear();
		m_vTouchHistories = vNewHistories;
		
		return vRVal;
	}

	private GestureInfo CheckPinchSpreadScrollGestures()
	{
		GestureInfo rRVal = new GestureInfo();
		rRVal.m_eGestureName = GestureName.GESTURE_NONE;
		rRVal.m_vGestureData_1 = Vector3.zero;
		rRVal.m_fGestureData_2 = 0.0f;

		int iTouches = GetTouchesCountFromType_Internal(PlatformFamily.INPUT_TOUCH);
		if(iTouches > 1)
		{
			// è importante che se siamo in presenza di più di due tocchi vengano presi in considerazione sempre i due che hanno cominciato il gesto.
			bool bReset = false;
			SV_TouchInfo rFirstTouch = GetTouchInfo(m_vCurrentTouches[(int)PlatformFamily.INPUT_TOUCH], m_vTouchIndex[0]);
			SV_TouchInfo rSecondTouch = GetTouchInfo(m_vCurrentTouches[(int)PlatformFamily.INPUT_TOUCH], m_vTouchIndex[1]);
			
			if(rFirstTouch.m_iFingerIndex == -1 && rSecondTouch.m_iFingerIndex != -1)
			{
				rFirstTouch = SearchNewTouch(rSecondTouch.m_iFingerIndex);
				m_vTouchIndex[0] = rFirstTouch.m_iFingerIndex;
				bReset = true;
			}
			else if(rFirstTouch.m_iFingerIndex != -1 && rSecondTouch.m_iFingerIndex == -1)
			{
				rSecondTouch = SearchNewTouch(rFirstTouch.m_iFingerIndex);
				m_vTouchIndex[1] = rSecondTouch.m_iFingerIndex;
				bReset = true;
			}
			else if(rFirstTouch.m_iFingerIndex == -1 && rSecondTouch.m_iFingerIndex == -1)
			{
				rFirstTouch = m_vCurrentTouches[(int)PlatformFamily.INPUT_TOUCH][0];
				rSecondTouch = m_vCurrentTouches[(int)PlatformFamily.INPUT_TOUCH][1];
				m_vTouchIndex[0] = rFirstTouch.m_iFingerIndex;
				m_vTouchIndex[1] = rSecondTouch.m_iFingerIndex;
				bReset = true;
			}
						
			if(bReset)
				m_fStartDistance = Vector3.Distance(rFirstTouch.m_vPosition, rSecondTouch.m_vPosition);
			
			float fCurrentDistance = Vector3.Distance(rFirstTouch.m_vPosition, rSecondTouch.m_vPosition);
			if(fCurrentDistance < (m_fStartDistance-m_fPinchSpreadDistance))
			{
				rRVal.m_eGestureName = GestureName.GESTURE_PINCH;
				m_fStartDistance = fCurrentDistance;
			}
			else if(fCurrentDistance > (m_fStartDistance+m_fPinchSpreadDistance))
			{
				rRVal.m_eGestureName = GestureName.GESTURE_SPREAD;
				m_fStartDistance = fCurrentDistance;
			}
			
			rRVal.m_vGestureData_1 = (rFirstTouch.m_vPosition + rSecondTouch.m_vPosition) * 0.5f;
		}
		else if(iTouches == 1)
		{
			rRVal.m_eGestureName = GestureName.GESTURE_SCROLL;
			rRVal.m_vGestureData_1 = m_vCurrentTouches[(int)PlatformFamily.INPUT_TOUCH][0].m_vPosition;
		}
		else
		{
			m_vTouchIndex[0] = -1;
			m_vTouchIndex[1] = -1;
		}
		
		return rRVal;
	}
	
	private SV_TouchInfo SearchNewTouch(int iIndexToAvoid)
	{
		SV_TouchInfo rRVal = new SV_TouchInfo();
		for(int iPointer = 0; iPointer < m_vCurrentTouches.Length; ++iPointer)
		{
			if(m_vCurrentTouches[(int)PlatformFamily.INPUT_TOUCH][iPointer].m_iFingerIndex != iIndexToAvoid)
			{
				rRVal = m_vCurrentTouches[(int)PlatformFamily.INPUT_TOUCH][iPointer];
				break;
			}
		}
		
		return rRVal;
	}
	
	#endregion

	
	#region Gamepad
	
	public GPButtonStateName GetGamepadButtonState(GPButtonName eGamepadButton)
	{
		GPButtonStateName eRVal = GPButtonStateName.GBS_NONE;
		GamepadButtonState rButtonState = null;
		
		if(m_sDictGamepadButtonStates.TryGetValue(eGamepadButton, out rButtonState))
			eRVal = rButtonState.ButtonState;
		
		return eRVal;
	}
	
	private void UpdateGamepadState()
	{
		if( ActiveDevice_Internal != PlatformFamily.INPUT_MOUSE || ActiveDevice_Internal != PlatformFamily.INPUT_TOUCH )
		{
			string strPlatform = (Application.platform == RuntimePlatform.Android) ? "Android_" : "Win32_";
			float fTimeStep = Time.realtimeSinceStartup-m_fPreviousTimestamp;
			m_fPreviousTimestamp = Time.realtimeSinceStartup;
			
				// pointer update
			m_vGamepadPointerPos.x += Input.GetAxis(strPlatform+m_strLeftStickNames[0])*m_fGamepadPointerSpeed*m_fGamepadPointerSpeedRatio*fTimeStep;
			if(m_vGamepadPointerPos.x < 0)
				m_vGamepadPointerPos.x = 0;
			if(m_vGamepadPointerPos.x >= Screen.width)
				m_vGamepadPointerPos.x = Screen.width;
					
			m_vGamepadPointerPos.y += Input.GetAxis(strPlatform+m_strLeftStickNames[1])*m_fGamepadPointerSpeed*m_fGamepadPointerSpeedRatio*fTimeStep;
			if(m_vGamepadPointerPos.y < 0)
				m_vGamepadPointerPos.y = 0;
			if(m_vGamepadPointerPos.y >= Screen.height)
				m_vGamepadPointerPos.y = Screen.height;
			
			m_fGamepadPointerSpeedRatio = 1.0f;
			
				// buttons update
			foreach(KeyValuePair<GPButtonName, GamepadButtonState> rKeyValue in m_sDictGamepadButtonStates)
				rKeyValue.Value.Update();
		}
	}
	
	#endregion
	
	
	#region Keyboard
	
	public void AddKeyboardButton(KeyCode eKeyboardButton)
	{
		if(!m_sDictKeyboardButtonStates.ContainsKey(eKeyboardButton))
			m_sDictKeyboardButtonStates.Add(eKeyboardButton, new KeyboardButtonState(eKeyboardButton));
	}
	
	public void RemoveKeyboardButton(KeyCode eKeyboardButton)
	{
		if(m_sDictKeyboardButtonStates.ContainsKey(eKeyboardButton))
			m_sDictKeyboardButtonStates.Remove(eKeyboardButton);
	}
	
	public GPButtonStateName GetKeyboardButtonState(KeyCode eKeyboardButton)
	{
		GPButtonStateName eRVal = GPButtonStateName.GBS_NONE;
		KeyboardButtonState rButtonState = null;
		
		if(m_sDictKeyboardButtonStates.TryGetValue(eKeyboardButton, out rButtonState))
			eRVal = rButtonState.ButtonState;
		
		return eRVal;
	}
	
	private void UpdateKeyboardState()
	{
		foreach(KeyValuePair<KeyCode, KeyboardButtonState> rKeyValue in m_sDictKeyboardButtonStates )
			rKeyValue.Value.Update();
	}
	
	#endregion
		
	
	#region Singleton
	
	private static BM_InputManager		m_rManagerReference = null;
	
	public static BM_InputManager Instance()
	{
		if(m_rManagerReference == null)
			Debug.LogWarning("SV_InputManager.Instance() -> Manager non inizializzato! ERRORE!");
		return m_rManagerReference;
	}
	
	#endregion
}
